package com.hsjk.szwj.module.pay.service;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.hsjk.szwj.framework.common.constant.CommonConstant;
import com.hsjk.szwj.framework.mq.core.RedisDelayedQueue;
import com.hsjk.szwj.module.member.api.user.MemberUserApi;
import com.hsjk.szwj.module.member.api.user.dto.MemberUserRespDTO;
import com.hsjk.szwj.module.pay.constant.PayOrderConstant;
import com.hsjk.szwj.module.pay.controller.app.transfer.vo.TransferOrderReqVO;
import com.hsjk.szwj.module.pay.dal.dataobject.CommonPayResult;
import com.hsjk.szwj.module.pay.dal.dataobject.config.PayOrderDivisionMQ;
import com.hsjk.szwj.module.pay.dal.dataobject.order.PayOrderDO;
import com.hsjk.szwj.module.pay.enums.IfCodeEnum;
import com.hsjk.szwj.module.pay.mq.delayed.PayOrderDivisionListener;
import com.hsjk.szwj.module.pay.util.AmountUtil;
import com.hsjk.szwj.module.system.api.service.IServiceApi;
import com.hsjk.szwj.module.system.api.service.dto.ServiceDTO;
import com.hsjk.szwj.module.train.api.ICheckoutConfigApi;
import com.hsjk.szwj.module.train.api.ICheckoutOrderApi;
import com.hsjk.szwj.module.train.api.IClassApi;
import com.hsjk.szwj.module.train.api.ICourseApi;
import com.hsjk.szwj.module.train.api.IMemberServiceApi;
import com.hsjk.szwj.module.train.api.IOrderApi;
import com.hsjk.szwj.module.train.api.IProductApi;
import com.hsjk.szwj.module.train.api.ISkuDivisionApi;
import com.hsjk.szwj.module.train.api.IStudentApi;
import com.hsjk.szwj.module.train.api.dto.CheckoutConfigDTO;
import com.hsjk.szwj.module.train.api.dto.CheckoutOrderDTO;
import com.hsjk.szwj.module.train.api.dto.ClassDTO;
import com.hsjk.szwj.module.train.api.dto.CourseDTO;
import com.hsjk.szwj.module.train.api.dto.DivisionReceiverDTO;
import com.hsjk.szwj.module.train.api.dto.MemberCourseMappingDTO;
import com.hsjk.szwj.module.train.api.dto.MemberServiceMappingDTO;
import com.hsjk.szwj.module.train.api.dto.OrderDTO;
import com.hsjk.szwj.module.train.api.dto.OrderUpdateDTO;
import com.hsjk.szwj.module.train.api.dto.ProductSkuBindDTO;
import com.hsjk.szwj.module.train.api.dto.ProductSkuDTO;
import com.hsjk.szwj.module.train.api.dto.StudentInfoDTO;
import com.hsjk.szwj.module.train.api.dto.UpdateCheckoutOrderDTO;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;

/**
 * @author chenjiawei
 * @desc 订单处理通用逻辑
 * @Date 2023/08/22 13:39
 **/
@Service
@Slf4j
public class PayOrderProcessService {
    @Resource
    private PayOrderService payOrderService;
    @Resource
    private PayMchNotifyService payMchNotifyService;
    @Resource
    private RedisDelayedQueue redisDelayedQueue;
    @Resource
    private IOrderApi orderApi;
    @Resource
    private IProductApi productApi;
    @Resource
    private ICourseApi courseApi;
    @Resource
    private IMemberServiceApi memberServiceApi;
    @Resource
    private IServiceApi serviceApi;
    @Resource
    private IClassApi classApi;
    @Resource
    private IStudentApi studentApi;
    @Resource
    private ICheckoutConfigApi checkoutConfigApi;
    @Resource
    private MemberUserApi memberUserApi;
    @Resource
    private ICheckoutOrderApi checkoutOrderApi;

    @Resource
    private ITransferOrderService orderService;

    @Resource
    private ISkuDivisionApi skuDivisionApi;

    /**
     * 计算分润金额
     *
     * @param originPrice 订单原价
     * @param mode        计算模式 amount-金额 percent-百分比
     * @param value       数值
     * @return 金额
     */
    private Long calcAmount(Long originPrice, String mode, Long value) {
        String amountName = "amount";
        String percentName = "percent";

        if (amountName.equals(mode)) {
            // 具体金额
            return value;
        } else if (percentName.equals(mode)) {
            // 百分比
            return originPrice * value / 100;
        }
        return null;
    }

    private Long calcAmount(Long originPrice, DivisionReceiverDTO dto) {
        Long amount = 0L;
        if (CommonConstant.DIVISION_MODEL_AMOUNT.equals(dto.getDivisionModel())) {
            amount = dto.getDivisionAmount();
        } else if (CommonConstant.DIVISION_MODEL_PERCENTAGE.equals(dto.getDivisionModel())) {
            amount = AmountUtil.calPercentageFee(originPrice,
                    dto.getDivisionProfit(), BigDecimal.ROUND_FLOOR);
        }
        return amount;
    }

    /**
     * 创建动态分润结算单
     *
     * @param order        订单
     * @param bonusConfig  分润配置
     * @param member       分润的目标用户
     * @param checkoutType 分润类型
     */
    private CheckoutOrderDTO createDynamicCheckoutOrder(OrderDTO order, String bonusConfig, MemberUserRespDTO member,
                                                        String checkoutType) {
        JSONObject jsonObject = JSONUtil.parseObj(bonusConfig);
        log.info("createDynamicCheckoutOrder-jsonObject:{}", jsonObject);
        CheckoutOrderDTO checkoutOrderDTO = null;
        // 计算分润金额
        String mode = jsonObject.getStr("mode");
        Long value = jsonObject.getLong("value");
        Long calcAmount = calcAmount(order.getOrderPrice(), mode, value);
        log.info("createDynamicCheckoutOrder-calcAmount:{}", calcAmount);
        if (calcAmount != null && order.getOrderPrice() > calcAmount) {
            checkoutOrderDTO = new CheckoutOrderDTO();
            checkoutOrderDTO.setMemberId(member.getId());
            checkoutOrderDTO.setTrainOrderId(order.getId());
            checkoutOrderDTO.setCheckoutType(checkoutType);
            checkoutOrderDTO.setCheckoutPath(CommonConstant.CHECKOUT_PATH_TRANSFER);
            checkoutOrderDTO.setCheckoutAccount(member.getOpenId());
            checkoutOrderDTO.setCheckoutAmount(calcAmount);
            checkoutOrderDTO.setCheckoutDelay(jsonObject.getInt("delay"));
            checkoutOrderDTO.setTenantId(member.getTenantId());
        }
        //检查是否重复生成
        if (checkoutOrderDTO != null) {
            Boolean ifRepeat = checkoutOrderApi.checkIfRepeat(checkoutOrderDTO);
            if (ifRepeat) {
                return null;
            }
        }
        return checkoutOrderDTO;
    }

    /**
     * 创建固定分润结算单
     *
     * @return 结算单列表
     */
    private List<CheckoutOrderDTO> createFixedCheckoutOrder(OrderDTO order, List<DivisionReceiverDTO> skuDivisionList) {
        List<CheckoutOrderDTO> checkoutOrderDTOS = new ArrayList<>();
        for (DivisionReceiverDTO dto : skuDivisionList) {
            Long calcAmount = calcAmount(order.getOrderPrice(), dto);
            CheckoutOrderDTO checkoutOrderDTO = new CheckoutOrderDTO();
            checkoutOrderDTO.setTrainOrderId(order.getId());
            // 分账类型，目前都写死是固定分账
            checkoutOrderDTO.setCheckoutType(CommonConstant.CHECKOUT_TYPE_FIXED);
            checkoutOrderDTO.setCheckoutPath(CommonConstant.CHECKOUT_PATH_DIVIDE);
            checkoutOrderDTO.setCheckoutAmount(calcAmount);
            checkoutOrderDTO.setDivisionReceiverId(dto.getMchDivisionReceiverId());
            // 分润延迟天数
            checkoutOrderDTO.setCheckoutDelay(0);
            // 租户id
            checkoutOrderDTO.setTenantId(order.getTenantId());
            Boolean ifRepeat = checkoutOrderApi.checkIfRepeat(checkoutOrderDTO);
            if (!ifRepeat) {
                checkoutOrderDTOS.add(checkoutOrderDTO);
            }
        }
        return checkoutOrderDTOS;
    }

    /**
     * 生成结算单
     */
    public void genAllCheckoutOrder(OrderDTO orderdto) {
        // 生成结算单
        CheckoutConfigDTO checkoutConfig = checkoutConfigApi.getCheckoutConfigBySkuId(orderdto.getSkuId());
        log.info("checkoutConfig:" + checkoutConfig + ",skuid:" + orderdto.getSkuId());

        if (ObjectUtil.isNotNull(checkoutConfig)) {
            // 需要生成的结算单列表
            ArrayList<CheckoutOrderDTO> waitingToGenCheckoutOrders = new ArrayList<>();
            // 签单人和邀请人结算单
            if (ObjectUtil.isNotNull(orderdto.getSignMemberId())) {
                MemberUserRespDTO signMember = memberUserApi.getUser(orderdto.getSignMemberId());
                if (ObjectUtil.isNotNull(signMember)) {
                    // 签单人结算单（order.signMember）
                    String saleBonus = checkoutConfig.getSaleBonus();
                    if (StrUtil.isNotBlank(saleBonus)) {
                        CheckoutOrderDTO checkoutOrderDTO = createDynamicCheckoutOrder(orderdto, saleBonus, signMember,
                                CommonConstant.CHECKOUT_TYPE_SALE);
                        if (ObjectUtil.isNotNull(checkoutOrderDTO)) {
                            waitingToGenCheckoutOrders.add(checkoutOrderDTO);
                        }
                    }

                    // 邀请人结算单（order.signMember.inviterMember）
                    String inviteBonus = checkoutConfig.getInviteBonus();
                    if (StrUtil.isNotBlank(inviteBonus) && ObjectUtil.isNotNull(signMember.getInviterMemberId())) {
                        MemberUserRespDTO inviteMember = memberUserApi.getUser(signMember.getInviterMemberId());
                        if (ObjectUtil.isNotNull(inviteMember)) {
                            CheckoutOrderDTO checkoutOrderDTO = createDynamicCheckoutOrder(orderdto, inviteBonus, inviteMember,
                                    CommonConstant.CHECKOUT_TYPE_INVITE);
                            if (ObjectUtil.isNotNull(checkoutOrderDTO)) {
                                waitingToGenCheckoutOrders.add(checkoutOrderDTO);
                            }
                        }
                    }
                }
            }
            // 固定分润结算单
            List<DivisionReceiverDTO> skuDivisionList = skuDivisionApi.getSkuDivisionListBySkuId(orderdto.getSkuId());
            if (CollUtil.isNotEmpty(skuDivisionList)) {
                log.info("skuDivisionList-{}", skuDivisionList);
                List<CheckoutOrderDTO> fixedCheckoutOrders = createFixedCheckoutOrder(orderdto, skuDivisionList);
                waitingToGenCheckoutOrders.addAll(fixedCheckoutOrders);
            }
            if (CollUtil.isNotEmpty(waitingToGenCheckoutOrders)) {
                checkoutOrderApi.batchCreateCheckoutOrder(waitingToGenCheckoutOrders);
            } else {
                log.info("genAllCheckoutOrder-waitingToGenCheckoutOrders is empty");
            }
        }
    }

    /**
     * 明确成功的处理逻辑（除更新订单其他业务）
     **/
    public void confirmSuccess(PayOrderDO payOrder) {
        log.info("confirmSuccess");
        // 查询查询订单详情
        payOrder = payOrderService.getById(payOrder.getId());

        // 设置订单状态
        payOrder.setState(PayOrderConstant.STATE_SUCCESS);
        // 修改订单表状态
        OrderUpdateDTO orderDTO = new OrderUpdateDTO();
        orderDTO.setOrderNo(String.valueOf(payOrder.getMchOrderId()));
        orderDTO.setPayOrderId(payOrder.getId());
        orderDTO.setPayTime(LocalDateTime.now());
        orderDTO.setStatus(CommonConstant.ORDER_STATUS_PAYED);
        orderDTO.setPayChannelCode(payOrder.getWayCode());
        orderApi.updateOrderInfo(orderDTO);

        // 开通服务
        OrderDTO orderdto = orderApi.getOrderInfoByOrderNo(String.valueOf(payOrder.getMchOrderId()));
        if (ObjectUtil.isNotNull(orderdto)) {
            List<ProductSkuBindDTO> productSkuBindListBySkuId = productApi
                    .getProductSkuBindListBySkuId(orderdto.getSkuId());
            if (CollUtil.isNotEmpty(productSkuBindListBySkuId)) {
                for (ProductSkuBindDTO bindDTO : productSkuBindListBySkuId) {
                    if (CommonConstant.PRODUCT_SKU_BIND_TYPE_COURSE.equals(bindDTO.getBindType())) {
                        CourseDTO courseById = courseApi.getCourseById(bindDTO.getBindId());
                        if (ObjectUtil.isNotNull(courseById)) {
                            MemberCourseMappingDTO dto = new MemberCourseMappingDTO();
                            dto.setCourseId(bindDTO.getBindId());
                            dto.setMemberId(orderdto.getMemberId());
                            dto.setValidDays(courseById.getValidDays());
                            dto.setTenantId(orderdto.getTenantId());
                            courseApi.createMemberCourseMapping(dto);
                        }
                    } else if (CommonConstant.PRODUCT_SKU_BIND_TYPE_SERVICE.equals(bindDTO.getBindType())) {
                        ServiceDTO serviceById = serviceApi.getServiceById(bindDTO.getBindId());
                        if (ObjectUtil.isNotNull(serviceById)) {
                            MemberServiceMappingDTO serviceMappingDTO = new MemberServiceMappingDTO();
                            serviceMappingDTO.setServiceId(bindDTO.getBindId());
                            serviceMappingDTO.setMemberId(orderdto.getMemberId());
                            serviceMappingDTO.setValidDays(serviceById.getValidDays());
                            serviceMappingDTO.setTenantId(orderdto.getTenantId());
                            memberServiceApi.createMemberServiceMapping(serviceMappingDTO);
                        }
                    } else if (CommonConstant.PRODUCT_SKU_BIND_TYPE_CLASS.equals(bindDTO.getBindType())) {
                        ClassDTO classById = classApi.getClassById(bindDTO.getBindId());
                        if (ObjectUtil.isNotNull(classById)) {
                            String signUpInfo = orderdto.getSignUpInfo();
                            if (StrUtil.isNotBlank(signUpInfo)) {
                                JSONObject jsonObject = JSONUtil.parseObj(signUpInfo);
                                if (ObjectUtil.isNotNull(jsonObject)) {
                                    StudentInfoDTO studentInfoDTO = new StudentInfoDTO();
                                    studentInfoDTO.setGender(Integer.valueOf(jsonObject.getStr("gender")));
                                    studentInfoDTO.setName(jsonObject.getStr("name"));
                                    studentInfoDTO.setPhone(jsonObject.getStr("phone"));
                                    studentInfoDTO.setCarType(classById.getCarType());
                                    studentInfoDTO.setMemberId(orderdto.getMemberId());
                                    studentInfoDTO.setTenantId(orderdto.getTenantId());
                                    studentApi.createStudentInfo(studentInfoDTO);
                                }
                            }
                        }
                    }
                }
            }
        }

        // 生成结算单
        genAllCheckoutOrder(orderdto);
        // 处理转账逻辑
        this.handleTransfer(orderdto.getId(), orderdto.getSkuId(), orderdto.getPayOrderId());
        // 自动分账 处理逻辑， 不影响主订单任务
        this.updatePayOrderAutoDivision(payOrder);


        // 发送商户通知
        payMchNotifyService.payOrderNotify(payOrder);

    }

    private void handleTransfer(Long trainOrderId, Long skuId, Long payOrderId) {
        List<CheckoutOrderDTO> orderListById = checkoutOrderApi.getCheckoutOrderListById(trainOrderId, CommonConstant.CHECKOUT_PATH_TRANSFER);
        if (CollUtil.isNotEmpty(orderListById)) {
            ProductSkuDTO productSkuInfoById = productApi.getProductSkuInfoById(skuId);
            for (CheckoutOrderDTO dto : orderListById) {
                TransferOrderReqVO reqVO = new TransferOrderReqVO();
                reqVO.setAmount(dto.getCheckoutAmount());
                reqVO.setIfCode(IfCodeEnum.WXPAY.getCode());
                reqVO.setEntryType(CommonConstant.ENTRY_WX_CASH);
                reqVO.setAccountNo(dto.getCheckoutAccount());
                reqVO.setTransferDesc(productSkuInfoById.getSkuName());
                reqVO.setPayOrderId(payOrderId);
                CommonPayResult commonPayResult = orderService.transferOrder(reqVO);
                if (commonPayResult.getData() != null) {
                    JSONObject jsonObject = JSONUtil.parseObj(commonPayResult.getData());
                    if (ObjectUtil.isNotNull(jsonObject.get("channelOrderNo"))) {
                        UpdateCheckoutOrderDTO updateCheckoutOrderDTO = new UpdateCheckoutOrderDTO();
                        updateCheckoutOrderDTO.setId(dto.getId());
                        updateCheckoutOrderDTO.setStatus(CommonConstant.SETTLEMENT_STATUS_SETTLED);
                        checkoutOrderApi.updateCheckoutOrderStatusById(updateCheckoutOrderDTO);
                    }
                }
            }
        }
    }

    /**
     * 更新订单自动分账业务
     **/
    private void updatePayOrderAutoDivision(PayOrderDO payOrder) {
        log.info("updatePayOrderAutoDivision:{}", payOrder);
        try {

            // 默认不分账 || 其他非【自动分账】逻辑时， 不处理
            if (payOrder == null || payOrder.getDivisionMode() == null
                    || payOrder.getDivisionMode() != PayOrderConstant.DIVISION_MODE_AUTO) {
                return;
            }

            // 更新订单表分账状态为： 等待分账任务处理
            boolean updDivisionState = payOrderService.update(new LambdaUpdateWrapper<PayOrderDO>()
                    .set(PayOrderDO::getDivisionState, PayOrderConstant.DIVISION_STATE_WAIT_TASK)
                    .eq(PayOrderDO::getId, payOrder.getId())
                    .eq(PayOrderDO::getDivisionState, PayOrderConstant.DIVISION_STATE_UNHAPPEN));

            if (updDivisionState) {
                // 推送到分账MQ
                // 80s 后执行
                redisDelayedQueue.addQueueSeconds(PayOrderDivisionMQ.build(payOrder.getId(),
                                CommonConstant.YES, null, payOrder.getTenantId()),
                        80, PayOrderDivisionListener.class);
            }

        } catch (Exception e) {
            log.error("订单[{}]自动分账逻辑异常：", payOrder.getId(), e);
        }
    }
}
